home *** CD-ROM | disk | FTP | other *** search
/ 130 MIDI Tool Box / 130 MIDI Tool Box.iso / midimod1 / textwin.c < prev    next >
Text File  |  1993-04-10  |  14KB  |  603 lines

  1. /*
  2.  * TEXTWIN.C - Text-windowing system
  3.  * Turbo C 2.0
  4.  *
  5.  * Description: Provides a simple text-menuing interface. Includes pop-down
  6.  *              menus, and scrolling windows. To use, set up a main window
  7.  *              with the MainWindow() function.
  8.  *   eg. MainWindow("Title", 2, "Files", 'f', "Help", 'h');
  9.  *
  10.  *              Then set the commands and command-numbers for each menu use
  11.  *              the SetMenu function.
  12.  *   eg. SetMenu(0, 3, "Open",'o',0, "Close",'c',1, "Quit",'q',2);
  13.  *       SetMenu(1, 3, "Help",'h',3, "------------",-1,-1, "About",'a',4);
  14.  *
  15.  *              Now just make a call to Choice() and the number it returns
  16.  *              will be the command-number of the choice
  17.  *   eg. If Help|About is chosen, 4 will be returned.
  18.  *
  19.  *              If you want to get the user to select an option from a list
  20.  *              of options, make an array of strings with the option
  21.  *              descriptions in them (ensure final element is NULL). The
  22.  *              element number chosen will be returned (first element = 0)
  23.  *              after a call to ScrollChoice()
  24.  *   eg. If the array is a, and the maximum string length is l, make the call
  25.  *       ScrollChoice("BetterTitle", a, l);
  26.  *
  27.  *              To display test inside a box, call DrawBox() with a NULL-
  28.  *              terminated array of strings.
  29.  *   eg. If the array is a, call
  30.  *       DrawBox(a);
  31.  *
  32.  *              To display text inside a box, and then wait for a key to be
  33.  *              pressed, set up a NULL-terminated array of strings and call
  34.  *              the InfoBox() function
  35.  *   eg. If the array is a, make the call
  36.  *       InfoBox(a);
  37.  *
  38.  *              If you want to get input as well as print a box, make a call
  39.  *              to DialogBox(), if nothing is entered, a default string is
  40.  *              returned
  41.  *   eg. DialogBox(a, "C:\") would return "C:\" if nothing was entered.
  42.  *
  43.  *
  44.  * Author: Andrew Scott (Adrenalin Software)
  45.  *
  46.  * Date: 14/3/1993 ver 0.1
  47.  */
  48.  
  49. #include <conio.h>
  50. #include <stdlib.h>
  51. #include <stdio.h>
  52. #include <stdarg.h>
  53. #include <string.h>
  54. #include <ctype.h>
  55.  
  56. /* Maximum number of chars in a menu title */
  57. #define MAXMENUWIDTH 9
  58. /* Maximum number of chars in a menu command */
  59. #define MAXCOMMWIDTH 12
  60. /* Border graphics */
  61. #define CRNRTL '┌'
  62. #define CRNRTR '┐'
  63. #define CRNRBL '└'
  64. #define CRNRBR '┘'
  65. #define HORIBAR '─'
  66. #define VERTBAR '│'
  67.  
  68. typedef char *string;
  69.  
  70. struct MenuStruct {
  71.     char n[MAXCOMMWIDTH+1]; /* Item name ("" = no items) */
  72.     int k;                  /* Key-press selector (lower case) */
  73.     int x;                  /* Function reference number (-ve = no command) */
  74. };
  75. typedef struct MenuStruct *MenuItem;
  76.  
  77. struct MenuBar {
  78.     char n[MAXMENUWIDTH+1]; /* Menu name ("" = no menus) */
  79.     int k;                  /* Key-press selector (lower case) */
  80.     MenuItem m;             /* Menu items */
  81. } *Main;
  82.  
  83.  
  84. #if 0
  85. string parmlist(string bit, int n)
  86. {
  87.     string s, t;
  88.     int l;
  89.  
  90.     s = t = (string) malloc(1 + n * (l = strlen(bit)));
  91.     while (n--) {
  92.         strcpy(t, bit);
  93.         t += l;
  94.     }
  95.     return s;
  96. }
  97. #endif
  98.  
  99. void MainWindow(string title, int num, ...)
  100. /* Post: Screen is set up with a nice title and num menus */
  101. {
  102.     va_list args;
  103.     string t;
  104.     int i;
  105.     struct MenuBar *c;
  106.  
  107.     c = Main = (struct MenuBar *) malloc(sizeof(struct MenuBar) * (num + 1));
  108.     va_start(args, &num);
  109.     textmode(C80);
  110.     textcolor(CYAN);
  111.     textbackground(BLACK);
  112.     clrscr();
  113.     textbackground(BLUE);
  114.     textcolor(WHITE);
  115.     i = 80 - strlen(title);
  116.     cprintf("%*c%s%*c", i/2, ' ', title, i/2 + i%2, ' ');
  117.     textcolor(YELLOW);
  118.     cprintf(" ");
  119.     for (i = num; i--; c++) {
  120.         t = (va_arg(args, string));
  121.         strcpy(c->n, t);
  122.         cprintf("%-*s", MAXMENUWIDTH, t);
  123.         c->k = (va_arg(args, int));
  124.         c->m = NULL;
  125.     }
  126.     c->n[0] = 0;
  127.     cprintf("%*c", 79 - MAXMENUWIDTH * num, ' ');
  128.     va_end(args);
  129. }
  130.  
  131. void SetMenu(int menu, int n, ...)
  132. /* Post: n commands has been set in menu #menu (0 = 1st) */
  133. {
  134.     va_list args;
  135.     string t;
  136.     struct MenuBar *c1;
  137.     MenuItem c2;
  138.  
  139.     int i;
  140.  
  141.     for (i = menu, c1 = Main; i-- && c1->n[0] != 0; c1++);
  142.     if (! c1->n[0])
  143.         return; /* error */
  144.     c1->m = c2 = (MenuItem) malloc(sizeof(struct MenuStruct) * (n + 1));
  145.     va_start(args, &n);
  146.     for (; n--; c2++) {
  147.         t = va_arg(args, string);
  148.         strcpy(c2->n, t);
  149.         c2->k = va_arg(args, int);
  150.         c2->x = va_arg(args, int);
  151.     }
  152.     c2->n[0] = 0;
  153. }
  154.  
  155. int _Menulength_; /* ignore this unstructured global variable ;) */
  156.  
  157. void PrintMenu(MenuItem m, int x)
  158. /* Post: The menu which is pointed to by m is printed at column x */
  159. {
  160.     int i;
  161.     char t[MAXCOMMWIDTH + 3];
  162.  
  163.     i = MAXCOMMWIDTH+2;
  164.     t[i] = 0;
  165.     while (i--)
  166.         t[i] = HORIBAR;
  167.     textcolor(YELLOW);
  168.     textbackground(BLUE);
  169.     gotoxy(x, 3);
  170.     cprintf("%c%s%c", CRNRTL, t, CRNRTR);
  171.     _Menulength_ = 2;
  172.     i = 4;
  173.     while (m->n[0]) {
  174.         _Menulength_++;
  175.         gotoxy(x, i++);
  176.         cprintf("%c %-*s %c", VERTBAR, MAXCOMMWIDTH, (m++)->n, VERTBAR);
  177.     }
  178.     gotoxy(x, i);
  179.     cprintf("%c%s%c", CRNRBL, t, CRNRBR);
  180. }
  181.  
  182. void ClearMenu(int x)
  183. /* Post: The last menu printed at column x is now gone */
  184. {
  185.     int i = 3;
  186.  
  187.     textcolor(CYAN);
  188.     textbackground(BLACK);
  189.     while (_Menulength_--) {
  190.         gotoxy(x, i++);
  191.         cprintf("%*c", MAXCOMMWIDTH + 4, ' ');
  192.     }
  193. }
  194.  
  195. void PrintComm(MenuItem m, int x, int y)
  196. /* Post: Item *m is highlighted at column x, position y */
  197. {
  198.     gotoxy(x+1, y+4);
  199.     textcolor(MAGENTA);
  200.     textbackground(BLACK);
  201.     cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
  202. }
  203.  
  204. void ClearComm(MenuItem m, int x, int y)
  205. /* Post: Item *m is normalized at column x, position y */
  206. {
  207.     gotoxy(x+1, y+4);
  208.     textcolor(YELLOW);
  209.     textbackground(BLUE);
  210.     cprintf(" %-*s ", MAXCOMMWIDTH, m->n);
  211. }
  212.  
  213. void PrintBar(string s, int w, int y)
  214. /* Post: String s (width w) is highlighted in the text window on line y */
  215. {
  216.     gotoxy(1, y+1);
  217.     textcolor(WHITE);
  218.     textbackground(BLACK);
  219.     cprintf(" %-*s ", w, s);
  220. }
  221.  
  222. void ClearBar(string s, int w, int y)
  223. /* Post: String s (width w) is normalized in the text window on line y */
  224. {
  225.     gotoxy(1, y+1);
  226.     textcolor(BLACK);
  227.     textbackground(CYAN);
  228.     cprintf(" %-*s ", w, s);
  229. }
  230.  
  231. void Beep()
  232. /* Post: Speaker has made a beep */
  233. {
  234.     printf("%c", 7);
  235. }
  236.  
  237. int Choice()
  238. /*
  239.  * Returns: a function reference number corresponding to a chosen command,
  240.  *   but returns -1 on an error.
  241.  */
  242. {
  243.     int ch;
  244.     struct MenuBar *c;
  245.     MenuItem p, q;
  246.     int i, fx = -1, y;
  247.  
  248.     textcolor(CYAN);
  249.     textbackground(BLACK);
  250.     gotoxy(1, 25);
  251.     do {
  252.         cprintf("\rPress the letter of the menu you wish to select.");
  253.         ch = tolower(getch());
  254.         for (c = Main, i = 0; c->n[0] && c->k != ch; c++, i++);
  255.         i = 2 + MAXMENUWIDTH * i;
  256.         if (c->n[0] != 0)
  257.             do {
  258.                 cprintf("\rPress a letter, or use cursor keys and <RETURN> to select a command.");
  259.                 gotoxy(i, 2);
  260.                 textbackground(BLUE);
  261.                 textcolor(LIGHTRED);
  262.                 cprintf("%-*s", MAXMENUWIDTH, c->n);
  263.                 PrintMenu(p = c->m, i);
  264.                 PrintComm(p, i, y = 0);
  265.                 do {
  266.                     ch = tolower(getch());
  267.                     if (!ch) {
  268.                         ch = -getch();
  269.                         if (ch==-72) /* up-arrow */
  270.                             if (!y)
  271.                                 Beep();
  272.                             else {
  273.                                 ClearComm(p--, i, y--);
  274.                                 PrintComm(p, i, y);
  275.                             }
  276.                         else if (ch==-80) /* down-arrow */
  277.                             if (! (p+1)->n[0])
  278.                                 Beep();
  279.                             else {
  280.                                 ClearComm(p++, i, y++);
  281.                                 PrintComm(p, i, y);
  282.                             }
  283.                     } else {
  284.                         for (q = c->m; q->n[0] && q->k != ch; q++);
  285.                         if (q->n[0])
  286.                             fx = q->x;
  287.                     }
  288.                 } while ((ch==-72 || ch==-80) && fx < 0);
  289.                 if (ch==13 && fx < 0)
  290.                     fx = p->x;
  291.                 ClearMenu(i);
  292.                 gotoxy(i, 2);
  293.                 textbackground(BLUE);
  294.                 textcolor(YELLOW);
  295.                 cprintf("%-*s", MAXMENUWIDTH, c->n);
  296.                 textcolor(CYAN);
  297.                 textbackground(BLACK);
  298.                 gotoxy(1, 25);
  299.                 cprintf("%52c", ' ');
  300.                 if (ch==-75)
  301.                     if (i==2)
  302.                         Beep();
  303.                     else {
  304.                         i -= MAXMENUWIDTH;
  305.                         c--;
  306.                     }
  307.                 else if (ch==-77)
  308.                     if (! (c+1)->n[0])
  309.                         Beep();
  310.                     else {
  311.                         i += MAXMENUWIDTH;
  312.                         c++;
  313.                     }
  314.             } while (ch != 27 && fx < 0);
  315.         clreol();
  316.     } while (fx < 0);
  317.     return fx;
  318. }
  319.  
  320. void ClearWin()
  321. /* Post: Area below command and title bars is clear */
  322. {
  323.     textcolor(CYAN);
  324.     textbackground(BLACK);
  325.     window(1, 3, 80, 25);
  326.     clrscr();
  327.     window(1, 1, 80, 25);
  328. }
  329.  
  330. int ScrollChoice(string title, string *sp, int w)
  331. /*
  332.  * Returns: The offset of the string from s which is chosen, -1 on none
  333.  *    s points to the start of a list of strings, max length w, NULL term.
  334.  */
  335. {
  336.     string s, t, *srt, *end;
  337.     int l, p, cur, ch, x = -1;
  338.  
  339.     if (strlen(title) > w)
  340.         w = strlen(title);
  341.     textcolor(CYAN);
  342.     textbackground(BLACK);
  343.     gotoxy(1, 25);
  344.     cprintf("Use cursor keys and <RETURN> to make a selection.");
  345.     s = t = (string) malloc(w + 3);
  346.     for (p = w+2; p--; *(t++) = HORIBAR);
  347.     *t = 0;
  348.     gotoxy(5,3);
  349.     textcolor(BLACK);
  350.     textbackground(CYAN);
  351.     cprintf("%c%s%c", CRNRTL, s, CRNRTR);
  352.     gotoxy(6 + (w - strlen(title))/2, 3);
  353.     cprintf(" %s ", title);
  354.     srt = end = sp;
  355.     for (end = sp, l = 0; *end!=NULL && l<20; l++) {
  356.         gotoxy(5, l+4);
  357.         cprintf("%c %-*s %c", VERTBAR, w, *(end++), VERTBAR);
  358.     }
  359.     end--;
  360.     gotoxy(5, l+4);
  361.     cprintf("%c%s%c", CRNRBL, s, CRNRBR);
  362.     free(s);
  363.     window(6, 4, 8+w, l+3);
  364.     PrintBar(*srt, w, p = 0);
  365.     cur = 0;
  366.     x = -1;
  367.     do {
  368.         ch = tolower(getch());
  369.         if (!ch) {
  370.             ch = -getch();
  371.             if (ch==-72)
  372.                 if (!cur)
  373.                     Beep();
  374.                 else if (p) {
  375.                     ClearBar(*(srt+p), w, p);
  376.                     p--;
  377.                     PrintBar(*(srt+p), w, p);
  378.                     cur--;
  379.                 } else {
  380.                     ClearBar(*(srt--), w, 0);
  381.                     gotoxy(1, 1);
  382.                     insline();
  383.                     gotoxy(w+3, 1);
  384.                     cprintf("%c", VERTBAR);
  385.                     PrintBar(*srt, w, 0);
  386.                     end--;
  387.                     cur--;
  388.                 }
  389.             else if (ch==-80)
  390.                 if (p==l-1 && *(end+1)==NULL)
  391.                     Beep();
  392.                 else if (p < l-1) {
  393.                     ClearBar(*(srt+p), w, p);
  394.                     p++;
  395.                     cur++;
  396.                     PrintBar(*(srt+p), w, p);
  397.                 } else {
  398.                     ClearBar(*end, w, p);
  399.                     end++;
  400.                     gotoxy(w+3, l);
  401.                     cprintf("%c", VERTBAR);  /* argh.. cant print at final corner */
  402.                     cur++;
  403.                     PrintBar(*end, w, p);
  404.                     srt++;
  405.                 }
  406.         } else if (ch==13)
  407.             x = cur;
  408.     } while (x < 0 && ch != 27);
  409.     ClearWin();
  410.     return x;
  411. }
  412.  
  413. void PrintBox(string *sp, int *x1, int *y1, int *w1)
  414. /*
  415.  * Post: The NULL-terminated array of strings pointed to by sp is printed,
  416.  *    and x1, y1 are set to be the co-ordinates of the bottom-left corner,
  417.  *    w1 is set to be the width of the inside of the box.
  418.  */
  419. {
  420.     int w, x, i, j;
  421.     string s, t, *c;
  422.  
  423.     if (*sp==NULL)
  424.         return;
  425.     c = sp;
  426.     for (w = strlen(*(c++)), i = 1; *c!=NULL; c++, i++)
  427.         if (w < (x = strlen(*c)))
  428.             w = x;
  429.     *w1 = w + 2;
  430.     *x1 = 1 + (x = (76 - w)/2);
  431.     i = 3 + (21 - i)/2;
  432.     s = t = (string) malloc(w+3);
  433.     for (j = w+2; j--; *(t++) = HORIBAR);
  434.     *t = 0;
  435.     textcolor(BLACK);
  436.     textbackground(CYAN);
  437.     gotoxy(x, i++);
  438.     cprintf("%c%s%c", CRNRTL, s, CRNRTR);
  439.     for (c = sp; *c!=NULL; c++) {
  440.         gotoxy(x, i++);
  441.         cprintf("%c %-*s %c", VERTBAR, w, *c, VERTBAR);
  442.     }
  443.     *y1 = i-1;
  444.     gotoxy(x, i);
  445.     cprintf("%c%s%c", CRNRBL, s, CRNRBR);
  446.     free(s);
  447. }
  448.  
  449. void DrawBox(string *sp)
  450. /* Post: The NULL-terminated array of strings pointed to by sp is printed */
  451. {
  452.     int i;
  453.  
  454.     PrintBox(sp, &i, &i, &i);
  455. }
  456.  
  457. char InfoBox(string *sp)
  458. /*
  459.  * Returns: The key pressed after the NULL-terminated array of strings
  460.  *    pointed to by sp is printed.
  461.  */
  462. {
  463.     int k;
  464.  
  465.     DrawBox(sp);
  466.     textcolor(CYAN);
  467.     textbackground(BLACK);
  468.     gotoxy(1, 25);
  469.     cprintf("Please press a key.");
  470.     k = getch();
  471.     ClearWin();
  472.     return k;
  473. }
  474.  
  475. string DialogBox(string *sp, string def)
  476. /* Pre: def != NULL */
  477. /*
  478.  * Returns: The string entered (or def if none entered), after printing
  479.  *    box filled with NULL-terminated strings sp.
  480.  */
  481. {
  482.     int x, y, w, ch, i=0;
  483.     string s;
  484.  
  485.     PrintBox(sp, &x, &y, &w);
  486.     s = (string) malloc(w+1);
  487.     strcpy(s, def);
  488.     textcolor(CYAN);
  489.     textbackground(BLACK);
  490.     gotoxy(1, 25);
  491.     cprintf("Enter text, and when you are finished, press <RETURN>.");
  492.     textcolor(WHITE);
  493.     gotoxy(x, y);
  494.     cprintf("%-*s", w, s);
  495.     window(x, y, x+w-1, y);
  496.     gotoxy(1, 1);
  497.     x = strlen(s);
  498.     do {
  499.         if (!(ch = getch()))
  500.             ch = -getch();
  501.         if (ch==8 || ch==127)
  502.             if (!i)
  503.                 Beep();
  504.             else {
  505.                 cprintf("\b");
  506.                 clreol();
  507.                 x = --i;
  508.             }
  509.         else if (ch==-75)
  510.             if (!i)
  511.                 Beep();
  512.             else {
  513.                 cprintf("\b");
  514.                 i--;
  515.             }
  516.         else if (ch==-77)
  517.             if (i==x)
  518.                 Beep();
  519.             else {
  520.                 cprintf("%c", s[i]);
  521.                 i++;
  522.             }
  523.         else if (ch!=13 && ch!=27)
  524.             if (i==w-1)
  525.                 Beep();
  526.             else {
  527.                 cprintf("%c", ch);
  528.                 if (i==x)
  529.                     x++;
  530.                 s[i++] = ch;
  531.             }
  532.     } while (ch!=13 && ch!=27);
  533.     s[i] = 0;
  534.     if (ch==27) {
  535.         free(s);
  536.         strcpy(s = (string) malloc(strlen(def)+1), def);
  537.     }
  538.     ClearWin();
  539.     return s;
  540. }
  541.  
  542. /*
  543.  * This main function is for testing the basics of these routines.
  544.  * Leave it commented out when creating object files.
  545.  *
  546. main()
  547. {
  548.     string scrolly[] = {
  549.         "First one",
  550.         "Second option",
  551.         "3rd",
  552.         "4th",
  553.         "Fifth",
  554.         "This could go on for AGES",
  555.         "Why not stop soon?",
  556.         "Ok",
  557.         "How about the next one",
  558.         "Done",
  559.         "Nope",
  560.         "Here's another few..",
  561.         "Un",
  562.         "Deux",
  563.         "Trois",
  564.         "Quatre",
  565.         "When should I stop?",
  566.         "Not yet obviously.",
  567.         "Cinq",
  568.         "Six",
  569.         "Sept",
  570.         "I think that's enough",
  571.         "Well maybe one more.",
  572.         NULL
  573.     };
  574.     string diagbox[] = {
  575.         "Please enter some gibberish",
  576.         "below at the prompt please.",
  577.         "It WONT check your spelling.",
  578.         "",
  579.         "",
  580.         NULL
  581.     };
  582.     string s;
  583.  
  584.     MainWindow("Big Huge Title", 3, "Ace", 'a', "Bee", 'b', "seaCide", 'c');
  585.     SetMenu(0, 3, "First", 'f', 1, "------------", -1, -1, "Second", 's', 2);
  586.     SetMenu(1, 1, "Spelling", 's', 3);
  587.     SetMenu(2, 2, "I'd like", 'i', 4, "To be beside", 't', 5);
  588.     while (1)
  589.         switch (Choice()) {
  590.             case 1:
  591.                 ScrollChoice("Window Name", scrolly, 25);
  592.                 break;
  593.             case 3:
  594.                 s = DialogBox(diagbox, "sample");
  595.                 free(s);
  596.                 break;
  597.             case 5:
  598.                 exit(0);
  599.         }
  600. }
  601.  * Ok.. this ends the commented out part
  602.  */
  603.